#include "stdafx.h"
#include "win_window.h"

_SSL_BEGIN
_SSWINOSL_BEGIN

#define kDefaultWindowClassName _T("sswinos_window_cls")
#define kWindowObjectPtrObjectName _T("sswinos_win_window_ptr")

win_window::win_window(
	HINSTANCE inst /*= NULL*/,
	window_message_filter *msg_filter /*= NULL*/,
	const tstring &class_name /* =_T */
	)
: inst_(inst), message_filter_(msg_filter), class_name_(class_name)
{
	if(inst_ == NULL)
		inst_ = ::GetModuleHandle(NULL);
	if(class_name_.empty())
		class_name_ = kDefaultWindowClassName;
	window_ = NULL;
	in_my_msg_loop_ = false;
}

win_window::~win_window()
{
	destory();
}

bool win_window::create()
{
	if(is_valid())
		return false;

	if(!register_class_if_necessary())
		return false;

	window_ = ::CreateWindowEx(0, class_name_.c_str(), _T(""),
		WS_POPUP|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, 0, 0,
		NULL, NULL, inst_, NULL);
	if(window_ != NULL)
	{
		::SetProp(window_, kWindowObjectPtrObjectName, this);
	}
	return window_ != NULL;
}

bool win_window::is_valid() const
{
	return ::IsWindow(window_) ? true : false;
}

bool win_window::destory()
{
	if(!is_valid())
	{
		window_ = NULL;
		return true;
	}

	if(in_my_msg_loop_)
	{
		SendMessage(window_, WM_QUIT, 0, 0);
	}
	::DestroyWindow(window_);
	window_ = NULL;
	return true;
}

void win_window::msg_loop()
{
	if(!is_valid())
		return;
	in_my_msg_loop_ = true;
	MSG msg;
	while(::GetMessage(&msg, NULL, 0, 0))
	{
		::TranslateMessage(&msg);
		::DispatchMessage(&msg);
		if(!is_valid())
			break;
	}
	in_my_msg_loop_ = false;
}

HWND win_window::get_window() const
{
	return window_;
}

LRESULT win_window::window_proc(UINT msg, WPARAM wparam, LPARAM lparam, bool &handled)
{
	LRESULT ret = 0;
	if(message_filter_ != NULL)
	{
		ret = message_filter_->window_proc(msg, wparam, lparam, handled);
	}
	if(handled)
		return ret;
	return 0L;
}

bool win_window::register_class_if_necessary()
{
	WNDCLASSEX wnd_class_ex = { sizeof(WNDCLASSEX) };
	if(::GetClassInfoEx(inst_, class_name_.c_str(), &wnd_class_ex))
		return true;
	memset(&wnd_class_ex, 0, sizeof(WNDCLASSEX));
	wnd_class_ex.cbSize = sizeof(WNDCLASSEX);
	wnd_class_ex.style = CS_HREDRAW|CS_VREDRAW;
	wnd_class_ex.lpfnWndProc = ___window_proc___;
	wnd_class_ex.hInstance = inst_;
	wnd_class_ex.hCursor = ::LoadCursor(NULL, IDC_ARROW);
	wnd_class_ex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wnd_class_ex.lpszClassName = class_name_.c_str();
	return ::RegisterClassEx(&wnd_class_ex) != 0;
}

LRESULT CALLBACK win_window::___window_proc___(HWND window_h, UINT msg, WPARAM wparam, LPARAM lparam)
{
	bool handled = false;
	LRESULT ret = 0;
	win_window *thiz = (win_window *)::GetProp(window_h, kWindowObjectPtrObjectName);
	if(thiz != NULL)
		ret = thiz->window_proc(msg, wparam, lparam, handled);
	if(handled)
		return ret;
	return ::DefWindowProc(window_h, msg, wparam, lparam);
}

_SSWINOSL_END
_SSL_END
